package com.gopay.bis.icbc.bcdl.operation;

import java.io.IOException;

import com.gopay.common.cipher.utils.LoggerMaskUtils;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.exception.GopayException;

public class HttpTransportForSign {
	/** Logger for logging information. */
	protected Log log = LogFactory.getLog(this.getClass());
	/** Timeout constant. */
	private static final String TIMEOUT = "http.socket.timeout";
	/** Request host. */
	private String url = null;
	/** Connect timeout. */
	private String timeout = "10000";
	/** Default retry connect times. */
	private static final int DEFAULT_RETRY_CONN_TIMES = 1;
	/** Default retry connect times. */
	private int retryConnTimes = DEFAULT_RETRY_CONN_TIMES;
	/**
	 * Default constructor.
	 */
	public HttpTransportForSign() {
	}

	/**
	 * 将报文以byte数组形式发送到NC签名端口.
	 * 
	 * @param obj
	 *            必须为<code>byte[]</code>型, 需签名的数据.
	 * @return 签名结果页面, 签名数据包含在页面中, 请参考工行相关文档.
	 * @throws GopayException
	 */
	public Object submit(Object obj) throws GopayException {
		HttpClient client = new HttpClient();
		PostMethod method = new PostMethod(this.url);
		int statusCode = 0;
		byte[] responseBody = null;
		try {
			method.getParams().setParameter(
					HttpMethodParams.RETRY_HANDLER,
					new DefaultHttpMethodRetryHandler(this.retryConnTimes,
							false));
			method.getParams().setParameter(TIMEOUT, new Integer(10000));
			client.getParams().setParameter(TIMEOUT, new Integer(10000));
			client.getHttpConnectionManager().getParams()
					.setParameter(TIMEOUT, new Integer(this.timeout));
			byte[] requestByte = (byte[]) obj;
			method.setRequestHeader("Content-Length",
					String.valueOf(requestByte.length));
			method.setRequestHeader("Content-Type", "INFOSEC_SIGN/1.0");
			method.setRequestHeader("User-Agent", "Rich Powered/1.0");
			method.setRequestEntity(new ByteArrayRequestEntity(requestByte));

			log.info(url + "HttpTransportForSign向前置软件449发送报文,timeout=" + timeout);
			statusCode = client.executeMethod(method);
			responseBody = method.getResponseBody();
			// hougn 2017-11-28 敏感信息掩码 start
			String responseBodyLog = new String(responseBody);
			responseBodyLog = responseBodyLog.replace("<sign>", "").replace("</sign>","").trim();
			responseBodyLog = "<sign>" + LoggerMaskUtils.maskString(responseBodyLog) + "</sign>";
			log.info("HttpTransportForSign从前置软件449接收到加密密文: \n"
					+ responseBodyLog);
			// hougn 2017-11-28 敏感信息掩码 end
			if (statusCode != HttpStatus.SC_OK) {
				if (log.isErrorEnabled()) {
					log.error("Answer from [" + url + "] status code: ["
							+ statusCode + "] response contents: ["
							+ new String(responseBody) + "]");
				}
			}

			log.info("Answer: " + responseBodyLog);
			return new String(responseBody, "GBK").getBytes("UTF-8");
		} catch (HttpException e) {
			log.fatal("Fatal protocol error while try connect to [" + url
					+ "] with parameters: " + StringUtils.join(method.getParameters(),','));
			log.fatal("Trace: " + e.getMessage());
			log.info("严重***HttpTransportForSign未从前置软件449接收到加密密文");
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6047);
		} catch (IOException e) {
			log.fatal("Fatal transport error while try connect to [" + url
					+ "] with parameters: " + StringUtils.join(method.getParameters(),';'));
			log.fatal("Trace: " + e.getMessage());
			log.info("严重***HttpTransportForSign未从前置软件449接收到加密密文");
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6047);
		} finally {
			method.releaseConnection();
			client.getHttpConnectionManager().closeIdleConnections(0);
		}
	}

	/**
	 * Set timeout.
	 * 
	 * @param timeout
	 *            the timeout to set.
	 */
	public void setTimeout(String timeout) {
		this.timeout = timeout;
	}

	/**
	 * Set url of ICBC NC Server(with port).
	 * 
	 * @param url
	 *            the url to set.
	 */
	public void setUrl(String url) {
		this.url = url;
	}

	/**
	 * 重连次数设置.
	 * 
	 * @param retryConnTimes
	 *            the retryConnTimes to set.
	 */
	public void setRetryConnTimes(int retryConnTimes) {
		this.retryConnTimes = retryConnTimes;
	}
}
